package com.mufeng.gallery.flutter_gallery_saver

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.FileUtils
import android.provider.MediaStore
import android.text.format.DateUtils
import androidx.annotation.RequiresApi
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*

object GalleryUtils {

    private fun generateFile(context: Context, extension: String = "", name: String? = null): File {
        val storePath =  if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
            context.getExternalFilesDir(null)?.absolutePath + File.separator + Environment.DIRECTORY_PICTURES
        }else{
            Environment.getExternalStorageDirectory().absolutePath + File.separator + Environment.DIRECTORY_PICTURES
        }
        val appDir = File(storePath)
        if (!appDir.exists()) {
            appDir.mkdir()
        }
        var fileName = name?:System.currentTimeMillis().toString()
        if (extension.isNotEmpty()) {
            fileName += (".$extension")
        }
        return File(appDir, fileName)
    }

    fun saveImageToGallery(context: Context, bmp: Bitmap, quality: Int, name: String?, result: MethodChannel.Result) {
        val file = generateFile(context,"jpg", name = name)
        try {
            GlobalScope.launch(Dispatchers.IO){
                val fos = FileOutputStream(file)
                println("ImageGallerySaverPlugin $quality")
                bmp.compress(Bitmap.CompressFormat.JPEG, quality, fos)
                fos.flush()
                fos.close()
                GlobalScope.launch(Dispatchers.Main){
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
                        saveImageToGalleryR(context,"jpg", file, result)
                    }else{
                        val uri = Uri.fromFile(file)
                        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
                        bmp.recycle()
                        result.success(SaveResultModel(uri.toString().isNotEmpty(), uri.toString(), null).toHashMap())
                    }
                }
            }
        } catch (e: Exception) {
            result.success(SaveResultModel(false, null, e.toString()).toHashMap())
        }
    }

    fun saveImageToGalleryWithUrl(context: Context, path: String, result: MethodChannel.Result) {
        val file = generateFile(context,File(path).extension)
        try {
            GlobalScope.launch(Dispatchers.IO){
                File(path).copyTo(file)
                GlobalScope.launch(Dispatchers.Main){
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
                        saveImageToGalleryR(context,File(path).extension, file, result)
                    }else{
                        val uri = Uri.fromFile(file)
                        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
                        result.success(SaveResultModel(uri.toString().isNotEmpty(), uri.toString(), null).toHashMap())
                    }
                }
            }
        } catch (e: Exception) {
            result.success(SaveResultModel(false, null, e.toString()).toHashMap())
        }
    }

    @RequiresApi(Build.VERSION_CODES.R)
    private fun saveImageToGalleryR(context: Context,extension: String, file: File, result: MethodChannel.Result) {
        val mImageTime = System.currentTimeMillis()
        val imageDate: String = SimpleDateFormat("yyyyMMdd-HHmmss").format(Date(mImageTime))
        val SCREENSHOT_FILE_NAME_TEMPLATE = "gallery_%s.$extension"
        val mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate)
        val mimeType = when(extension){
            "png" -> "image/png"
            "bmp", "dib" -> "image/bmp"
            "gif" -> "image/gif"
            else -> "image/jpeg"
        }
        val values = ContentValues()
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + "gallery")
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName)
        values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
        values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000)
        values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000)
        values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000)
        values.put(MediaStore.MediaColumns.IS_PENDING, 1)
        val resolver = context.contentResolver
        val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        try {
            GlobalScope.launch(Dispatchers.IO){
                val out = resolver.openOutputStream(uri!!)
                val fileInputStream = FileInputStream(file)
                FileUtils.copy(fileInputStream, out!!)
                fileInputStream.close()
                out.close()
                GlobalScope.launch(Dispatchers.Main){
                    values.clear()
                    values.put(MediaStore.MediaColumns.IS_PENDING, 0)
                    values.putNull(MediaStore.MediaColumns.DATE_EXPIRES)
                    resolver.update(uri, values, null, null)
                    result.success(SaveResultModel(uri.toString().isNotEmpty(), UriUtils.getFileAbsolutePath(context, uri), null).toHashMap())
                }
            }

        }catch (e: IOException){
            resolver.delete(uri!!, null);
            result.success(SaveResultModel(false, null, e.toString()).toHashMap())
        }
    }

    fun saveVideoToGallery(context: Context, filePath: String, result: MethodChannel.Result) {
        try {
            GlobalScope.launch(Dispatchers.IO){
                val originalFile = File(filePath)
                val file = generateFile(context,originalFile.extension)
                originalFile.copyTo(file)
                GlobalScope.launch(Dispatchers.Main){
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
                        saveVideoToGalleryR(context, file, result)
                    }else {
                        val uri = Uri.fromFile(file)
                        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
                        result.success(
                            SaveResultModel(
                                uri.toString().isNotEmpty(),
                                uri.toString(),
                                null
                            ).toHashMap()
                        )
                    }
                }
            }
        }catch (e: Exception){
            result.success(SaveResultModel(false, null, e.toString()).toHashMap())
        }
    }

    @RequiresApi(Build.VERSION_CODES.R)
    private fun saveVideoToGalleryR(context: Context, file: File, result: MethodChannel.Result){
        val mImageTime = System.currentTimeMillis()
        val imageDate: String = SimpleDateFormat("yyyyMMdd-HHmmss").format(Date(mImageTime))
        val SCREENSHOT_FILE_NAME_TEMPLATE = "gallery_%s.mp4"
        val mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate)


        val values = ContentValues()
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + "gallery")
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName)
        values.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
        values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000)
        values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000)
        values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000)
        values.put(MediaStore.MediaColumns.IS_PENDING, 1)
        val resolver = context.contentResolver
        val uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values)

        try {
            GlobalScope.launch(Dispatchers.IO){
                val out = resolver.openOutputStream(uri!!)
                val fileInputStream = FileInputStream(file)
                FileUtils.copy(fileInputStream, out!!)
                fileInputStream.close()
                out.close()
                val filePath = UriUtils.getFileAbsolutePath(context, uri)
                GlobalScope.launch(Dispatchers.Main){
                    values.clear();
                    values.put(MediaStore.MediaColumns.IS_PENDING, 0)
                    values.putNull(MediaStore.MediaColumns.DATE_EXPIRES)
                    resolver.update(uri, values, null, null)

                    result.success(SaveResultModel(uri.toString().isNotEmpty(), filePath, null).toHashMap())
                }
            }

        }catch (e: IOException){
            resolver.delete(uri!!, null)
            result.success(SaveResultModel(false, null, e.toString()).toHashMap())
        }
    }

}